package miniproj.models.room;

import java.util.List;
import java.util.LinkedList;

import javax.xml.bind.annotation.*;

import miniproj.exception.CapacityException;
import miniproj.models.building.Building;
import miniproj.models.groups.Group;
import miniproj.models.groups.Teaching;
import miniproj.models.people.Student;
import miniproj.models.people.Teacher;
import miniproj.models.reservation.*;

/**
 * 
 * This abstract class represents the basis of the different types of rooms
 * 
 * @author Baptiste Viale
 * 
 */
public abstract class Room implements java.io.Serializable {

	private static final long serialVersionUID = 4452676336320590567L;

	@XmlElement
	private RoomId id;

	@XmlElement
	private int capacity;

	@XmlElement
	private Equipment[] equipments;

	protected int minCapacity = 0;
	protected int maxCapacity;

	protected Room() {
	}

	protected Room(Building building, int floor, int numRoom, int capacity,
			Equipment[] equipments) {
		this.id = new RoomId(building, floor, numRoom);
		this.capacity = capacity;
		this.equipments = equipments;
	}

	protected Room(RoomId id, int capacity, Equipment[] equipments) {
		this.id = id;
		this.capacity = capacity;
		this.equipments = equipments;
	}

	/**
	 * Return the room id.
	 * 
	 * @return the id
	 */
	public RoomId getId() {
		return this.id;
	}

	/**
	 * Return the room capacity.
	 * 
	 * @return the capacity
	 */
	public int getCapacity() {
		return this.capacity;
	}

	/**
	 * Return the equipments of the room.
	 * 
	 * @return the equipments
	 */
	public Equipment[] getEquipments() {
		return this.equipments;
	}

	/**
	 * Return the minimum required capacity for this type of room.
	 * 
	 * @return the minimum capacity
	 */
	public int getMinCapacity() {
		return this.minCapacity;
	}

	/**
	 * Return the maximum required capacity for this type of room.
	 * 
	 * @return the max capacity
	 */
	public int getMaxCapacity() {
		return this.maxCapacity;
	}

	@Override
	public boolean equals(Object room) {
		if (room == null || !room.getClass().equals(this.getClass()))
			return false;

		if (!((Room) room).getId().equals(this.getId()))
			return false;

		return true;
	}

	/**
	 * Book this room at a specific date, and return the associated Reservation
	 * object.
	 * 
	 * @param reservationName
	 *            The teacher who makes the reservation
	 * @param date
	 *            the date of the reservation
	 * @param lg
	 *            the list of groups
	 * @param reservations
	 *            the current list of reservations
	 * @param teaching
	 *            the teaching
	 * @return the reservation created
	 */
	public Reservation book(Teacher reservationName, Date date, List<Group> lg,
			LinkedList<Reservation> reservations, Teaching teaching) {
		List<Student> presentStudents = new LinkedList<Student>();

		for (Group g : lg)
			for (Student s : g.getStudents())
				if (!presentStudents.contains(s))
					presentStudents.add(s);

		if (presentStudents.size() > this.capacity)
			throw new CapacityException(this.capacity, presentStudents.size());

		for (Reservation r : reservations) {
			if (r.getRoom().equals(this) && r.getDate().equals(date))
				return null;

			// The teacher has already a reservation at this date !
			if (r.getDate().equals(date)
					&& r.getClient().equals(reservationName))
				return null;
		}

		return new Reservation(reservationName, date, this, teaching, lg);
	}

	public List<Reservation> multiBook(Teacher reservationName, Date date,
			List<Group> lg, LinkedList<Reservation> reservations,
			Teaching teaching, Date lastDate) {
		List<Reservation> newr = new LinkedList<Reservation>();

		if (!date.before(lastDate))
			return newr;

		Date d = date;
		while (d.before(lastDate)) {
			Reservation r;
			try {
				r = this.book(reservationName, (Date) d.clone(), lg,
						reservations, teaching);
				if (r != null)
					newr.add(r);
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}

			d.getDate().setTime(d.getDate().getTime() + (1000 * 3600 * 24 * 7));
		}

		return newr;
	}

	@Override
	public String toString() {
		String equipments = "";
		Equipment e;

		if (this.equipments == null || this.equipments.length == 0) {
			equipments = "nothing";
		} else {
			for (int i = 0; i < this.equipments.length; i++) {
				e = this.equipments[i];
				equipments += e.name()
						+ ((i == this.equipments.length - 1) ? "" : ", ");
			}
		}
		return "Room " + this.id + ", capacity of " + this.capacity
				+ " students, equiped with " + equipments;
	}

}
